package cn.kzgg.ymcc.service.impl;

import cn.kzgg.ymcc.doc.CourseDoc;
import cn.kzgg.ymcc.domain.*;
import cn.kzgg.ymcc.dto.CourseDto;
import cn.kzgg.ymcc.dto.MbxDto;
import cn.kzgg.ymcc.dto.MessageSmsDto;
import cn.kzgg.ymcc.dto.UserSmsDto;
import cn.kzgg.ymcc.feign.CourseSearchFeignClient;
import cn.kzgg.ymcc.feign.MediaFileFeignClient;
import cn.kzgg.ymcc.mapper.CourseMapper;
import cn.kzgg.ymcc.result.JSONResult;
import cn.kzgg.ymcc.service.*;
import cn.kzgg.ymcc.util.AssertUtil;
import cn.kzgg.ymcc.util.StrUtils;
import cn.kzgg.ymcc.vo.CourseDetailVo;
import cn.kzgg.ymcc.vo.CourseItemVo;
import cn.kzgg.ymcc.vo.CourseOrderVo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author kzgg
 * @since 2022-07-21
 */
@Service
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {


    @Autowired
    private ITeacherService teacherService;

    @Autowired
    private ICourseDetailService courseDetailService;

    @Autowired
    private ICourseMarketService courseMarketService;

    @Autowired
    private ICourseTeacherService courseTeacherService;

    @Autowired
    private ICourseResourceService courseResourceService;

    @Autowired
    private ICourseSummaryService courseSummaryService;

    @Autowired
    private ICourseTypeService courseTypeService;

    @Autowired
    private CourseSearchFeignClient courseSearchFeignClient;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private ICourseChapterService courseChapterService;

    @Autowired
    private MediaFileFeignClient mediaFileFeignClient;

    /**
     * 新增课程
     *
     * 1.参数校验
     * 2.课程不能被注册
     * 3.保存数据
     * 保存课程
     * 保存课程详情
     * 保存课程销售
     * 保存课程讲师
     * 保存课程资源
     * 初始化课程统计
     * 课程类型表中的课程数+1
     *
     * @param courseDto
     */
    @Override
    @Transactional
    public void save(CourseDto courseDto) {
        Course course = courseDto.getCourse();
        CourseDetail courseDetail = courseDto.getCourseDetail();
        CourseMarket courseMarket = courseDto.getCourseMarket();
        CourseResource courseResource = courseDto.getCourseResource();
        List<Long> teacharIds = courseDto.getTeacharIds();
        //1.参数校验 使用JSR303
        //2.课程不能被注册
        Course courseTmp = selectByName(course.getName());
        AssertUtil.isNull(courseTmp,"课程已存在");
        //3.保存数据
        //保存课程  在service默认初始化状态，登陆人，登录id
        course.setStatus(0);
        course.setLoginId(2L);
        course.setLoginUserName("yhptest");
        //讲师
        List<Teacher> teachers = teacherService.selectBatchIds(teacharIds);
        // 整成stream
        StringBuilder sb = new StringBuilder();
        teachers.forEach(teacher -> {
            sb.append(teacher.getName()).append(",");
        });
        course.setTeacherNames(sb.toString());
        /*List<Teacher> teachers = teacherService.selectBatchIds(teacharIds);
        Map<String, Teacher> map = teachers.stream().collect(Collectors.toMap(Teacher::getName, teacher -> teacher));
        course.setTeacherNames(map.toString());*/
        insert(course);
        //保存课程详情
        courseDetail.setId(course.getId());
        courseDetailService.insert(courseDetail);
        //保存课程销售
        courseMarket.setId(course.getId());
        courseMarketService.insert(courseMarket);
        //保存课程讲师
        teacharIds.forEach(id->{
            CourseTeacher courseTeacher = new CourseTeacher();
            courseTeacher.setCourseId(course.getId());
            courseTeacher.setTeacherId(id);
            courseTeacherService.insert(courseTeacher);
        });
        //保存课程资源
        courseResource.setCourseId(course.getId());
        courseResourceService.insert(courseResource);
        //初始化课程统计
        CourseSummary courseSummary = new CourseSummary();
        courseSummary.setId(course.getId());
        courseSummaryService.insert(courseSummary);
        //课程类型表中的课程数+1
        CourseType courseType = courseTypeService.selectById(course.getCourseTypeId());
        courseType.setTotalCount(courseType.getTotalCount() + 1);
        courseTypeService.updateById(courseType);

    }

    private Course selectByName(String name) {
        Wrapper<Course> tWrapper = new EntityWrapper<Course>();
        tWrapper.eq("name",name);
        return selectOne(tWrapper);
    }

    /**
     * 课程发布
     *
     * 1.根据课程Id查询课程，判断可是是否存在
     * 2.修改课程状态为上架，填写上架时间
     * 3.保存课程相关内容到Es
     *   3.1 为service-search编写feign接口 ymcc-api-search
     *   3.2 在课程微服务中，依赖ymcc-api-search
     *   3.3 使用feign远程调用search完成课程保存到Es中
     * @param courseId
     */
    @Override
    @Transactional
    public void onLineCourse(Long courseId) {
        //1.根据课程id判断课程是否存在
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course,"课程为空");
        //2.修改课程状态为上架，修改上架时间
        course.setStatus(1);
        course.setOnlineTime(new Date());
        updateById(course);
        //3.保存相关内容到es
        //3.1.给service-search编写feign接口ymcc-api-search
        //3.2.course微服务中导入ymcc-api-search
        //3.3.使用feign远程调用search保存需要保存的内容到Es
        CourseDoc courseDoc = new CourseDoc();
        CourseType courseType = courseTypeService.selectById(course.getCourseTypeId());
        CourseMarket courseMarket = courseMarketService.selectById(courseId);
        CourseSummary courseSummary = courseSummaryService.selectById(courseId);
        //需要并保存到Es的字段
        BeanUtils.copyProperties(courseMarket,courseDoc);
        BeanUtils.copyProperties(courseSummary,courseDoc);
        BeanUtils.copyProperties(course,courseDoc);
        //单独赋值不然会被覆盖
        courseDoc.setCourseTypeName(courseType.getName());
        String chargeName = courseMarket.getCharge() == 1 ? "免费" : "收费";
        courseDoc.setChargeName(chargeName);

        JSONResult jsonResult = courseSearchFeignClient.saveCourse(courseDoc);
        AssertUtil.isTrue(jsonResult.isSuccess(),"课程发布失败");

        /**
         * 消息发布
         */
        msgSend(courseDoc);

    }

    private void msgSend(CourseDoc courseDoc) {
        MessageSmsDto messageSmsDto = new MessageSmsDto();
        //发送消息
        messageSmsDto.setTitle("新课程发布："+courseDoc.getName());
        messageSmsDto.setContent("您关注的"+courseDoc.getCourseTypeName()+"已发布新课:"+courseDoc.getName()+"尝鲜地址："+
                        "<a href='localhost:6002/list.html?courseId="+courseDoc.getId());
        //选择要发送的人
        List<UserSmsDto> userSmsDtos = Arrays.asList(new UserSmsDto(1L,"13330964748"));
        //将消息发给
        messageSmsDto.setUsers(userSmsDtos);
        //将消息存到mq发送
        rocketMQTemplate.sendOneWay("msg-topic:msg-tags", JSON.toJSONString(messageSmsDto));
    }


    /**
     * 课程下架
     * 1.根据课程Id查询课程，判断可是是否存在
     * 3.删除es里的数据
     * @param courseId
     */
    @Override
    @Transactional
    public void offLineCourse(Long courseId) {
        //1.根据课程Id查询课程，判断可是是否存在
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course,"课程不存在");
        //2.修改状态
        course.setStatus(0);
        updateById(course);
        //3.删除es里保存的数据
        JSONResult jsonResult = courseSearchFeignClient.remCourse(courseId);
        AssertUtil.isTrue(jsonResult.isSuccess(),"课程下架失败");

    }

    /**
     * 课程详情
     *  思路：根据courseId将vo中所有该保存的数据保存到vo中，注意防御性编程
     *  其中章节要调用media微服务因此需要feign接口去调
     *
     * @param courseId
     * @return
     */
    @Override
    public CourseDetailVo CourseDetail(Long courseId) {
        //courseId不能为空
        AssertUtil.isNotNull(courseId,"非法访问！");
        //1.获取课程详情
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course,"非法访问!!");
        //课程必须上线
        Boolean onLine = course.getStatus()==1;
        AssertUtil.isTrue(onLine,"非法访问!!!");
        //分别获取销量细节和摘要的详情
        CourseMarket courseMarket = courseMarketService.selectById(courseId);
        CourseDetail courseDetail = courseDetailService.selectById(courseId);
        CourseSummary courseSummary = courseSummaryService.selectById(courseId);

        //获取讲师详情===========================
        Wrapper<CourseTeacher> cTWrapper = new EntityWrapper<>();
        cTWrapper.eq("course_id",courseId);
        List<CourseTeacher> courseTeachers = courseTeacherService.selectList(cTWrapper);
        List<Long> teacherId =
                courseTeachers.stream().map(courseTeacher -> courseTeacher.getTeacherId()).collect(Collectors.toList());
        List<Teacher> teachers = teacherService.selectBatchIds(teacherId);

        //获取章节详情================================
        Wrapper<CourseChapter> ccWrapper = new EntityWrapper<>();
        ccWrapper.eq("course_id",courseId);
        List<CourseChapter> courseChapters = courseChapterService.selectList(ccWrapper);
        courseChapters.forEach(courseChapter -> {
            JSONResult jsonResult = mediaFileFeignClient.courseDetail(courseChapter.getId());
            //如果jsonResult返回成功并且不为空，那就将jsonResult转为list
            if(jsonResult.isSuccess()&&jsonResult.getData()!=null){
                List<MediaFile> mediaFiles = JSONObject.parseArray(jsonResult.getData().toString(), MediaFile.class);
                courseChapter.getMediaFiles().addAll(mediaFiles);

            }
        });

        //将数据保存到vo
        CourseDetailVo vo = new CourseDetailVo();
        vo.setCourse(course);
        vo.setCourseChapters(courseChapters);
        vo.setCourseDetail(courseDetail);
        vo.setCourseMarket(courseMarket);
        vo.setCourseSummary(courseSummary);
        vo.setTeachers(courseTeachers);


        return vo;
    }

    /**
     * 课程订单信息
     *
     * 1.判断参数
     * 2.业务判断
     * 2.根据每个课程Id查询课程 + 销售表
     * 3.封装课程和销售成 CourseItemVo
     * 4.将封装好的List<CourseItemVo> + 总金额，封装成CourserOrderVo
     * @param courseIds
     * @return
     */
    @Override
    public CourseOrderVo CourseOrderInfo(String courseIds) {
        //1.判断参数
        String[] strIds = courseIds.split(",");
        AssertUtil.isNotNull(strIds,"课程不能为空");
        //2.业务判断
        //将字符串转为list
        List<Long> ids = StrUtils.splitStr2LongArr(courseIds);
        //去重
        Set<Long> setIds = ids.stream().collect(Collectors.toSet());
        //判断传过来的ids跟setIds是否相等，如果不等说明有重复的id
        boolean eq = ids.size()==setIds.size();
        AssertUtil.isTrue(eq,"请求非法");
        //3.根据每个课程Id查询课程 + 销售表
        List<CourseItemVo> courseInfos=new ArrayList<>();
        BigDecimal totalAmount=new BigDecimal(0);
        for (Long setId : setIds) {
            //查课程
            Course course = selectById(setId);
            AssertUtil.isNotNull(course,"请求非法！");
            //课程必须已上线
            boolean onLine = course.getStatus() == 1;
            AssertUtil.isTrue(onLine,"请求非法，课程未上线");
            //查销售表
            CourseMarket courseMarket = courseMarketService.selectById(setId);
            AssertUtil.isNotNull(courseMarket,"请求非法，没有销售");
            CourseItemVo courseItemVo = new CourseItemVo(course,courseMarket);
            //将对应的course和courseMarket存入CourseOrderVo
            courseInfos.add(courseItemVo);
            totalAmount=totalAmount.add(courseMarket.getPrice());
        }

        return new CourseOrderVo(courseInfos,totalAmount);
    }


}
